/*
 ----------------------------------------------------------------------------------
                           "THE BEER-WARE COPYRIGHT LICENSE"
                                     (Revision 43)
                                      -----------
    Rymek [rymek@rymek.org] wrote this file. As long as You retain this notice and
    this file has been sent directly to You by the author, You can do whatever You
    want with this stuff as long as You don't sell or rent it. If we meet some day,
    and You think this stuff is worth it, You can buy me a beer in return :-)
                                                                 __________
                                                                 Paweł Rymaszewski
  ----------------------------------------------------------------------------------
 */

package ui.windows.forms.searchResult;

import constants.Constants;
import constants.MessageConstants;
import constants.UiConstants;
import exceptions.NoMatchFoundException;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rtextarea.SearchEngine;
import processing.objects.Result;
import processing.objects.Results;
import utils.properties.Configuration;

import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * Class represents window for displaying parsed search results
 *
 * @author rymek
 *         User: Rymek
 *         Date: 24.07.11
 *         Time: 00:41
 */

public class SearchResultForm {

    private JPanel searchResult;
    private JPanel buttonsPanel;
    private JPanel searchPanel;

    private JScrollPane requestPanel;
    private JScrollPane responsePanel;

    public RSyntaxTextArea requestBody;
    public RSyntaxTextArea responseBody;
    private RSyntaxTextArea searchSource;

    private JButton saveRequest;
    private JButton saveResponse;
    private JButton merge;
    private JButton findIn;
    private JLabel findInLabel;

    private JTextField searchString;
    private JSplitPane resultSplitPane;
    private String oldSearchString;
    private boolean foundMatch = false;

    private final Result resultRequest;
    private final Result resultResponse;
    private final Results parsedResults;

    private JFrame resultForm;

    /**
     * Constructor.
     * Sets reference to all search parsedResults and displays resultRequest with given msgId
     *
     * @param requestResult resultRequest to display
     * @param results       parsed parsedResults
     */
    public SearchResultForm(Result requestResult, Results results) {

        this.parsedResults = results;

        this.resultRequest = requestResult;
        if (this.resultRequest.getMessageInfo().getMessageType() == MessageConstants.MSG_SYNC_MESSAGE) {
            this.resultResponse = results.getResults().get(MessageConstants.MSG_RESPONSE).get(resultRequest.getId());
        } else this.resultResponse = null;

        this.initializeResultFields();
        this.generateTitle(this.resultRequest);

        SearchResultFormActionListener searchResultFormActionListener = new SearchResultFormActionListener(this);
        this.saveRequest.addActionListener(searchResultFormActionListener);
        this.saveResponse.addActionListener(searchResultFormActionListener);
        this.merge.addActionListener(searchResultFormActionListener);
        this.findIn.addActionListener(searchResultFormActionListener);

        SearchResultFormKeyAdapter searchResultFormKeyAdapter = new SearchResultFormKeyAdapter(this);
        this.requestBody.addKeyListener(searchResultFormKeyAdapter);
        this.responseBody.addKeyListener(searchResultFormKeyAdapter);
        this.searchString.addKeyListener(searchResultFormKeyAdapter);

        this.resetFindIn();
    }

    /**
     * Sets XML fields to display resultRequest body
     */
    private void initializeResultFields() {

        switch (this.parsedResults.getSearchParameters().getMessageInfo().getMessageType()) {

            case MessageConstants.MSG_SYNC_MESSAGE: {

                try {

                    if (this.resultRequest == null) throw new IOException();
                    this.resultRequest.setXmlString(new String(Files.readAllBytes(Paths.get(Constants.TEMP_DIR + "\\" + this.parsedResults.getOutputDir() + "\\" + this.resultRequest.getXmlResultFile().getName()))));
                    this.requestBody.setText(this.resultRequest.getXmlString());
                    this.requestBody.setCaretPosition(0);

                } catch (IOException e) {
                    this.requestBody.setText(UiConstants.EMPTY_MESSAGE_STRING);
                }

                try {

                    if (this.resultResponse == null) throw new IOException();
                    this.resultResponse.setXmlString(new String(Files.readAllBytes(Paths.get(Constants.TEMP_DIR + "\\" + this.parsedResults.getOutputDir() + "\\" + this.resultResponse.getXmlResultFile().getName()))));
                    this.responseBody.setText(this.resultResponse.getXmlString());
                    this.responseBody.setCaretPosition(0);

                } catch (IOException e) {
                    this.responseBody.setText(UiConstants.EMPTY_MESSAGE_STRING);
                }

                this.responsePanel.setVisible(true);
                this.responseBody.setVisible(true);
                break;
            }

            case MessageConstants.MSG_ASYNC_MESSAGE: {

                this.saveResponse.setVisible(false);
                this.merge.setVisible(false);
                this.responsePanel.setVisible(false);
                this.responseBody.setVisible(false);

                try {

                    if (this.resultRequest == null) throw new IOException();
                    this.resultRequest.setXmlString(new String(Files.readAllBytes(Paths.get(Constants.TEMP_DIR + "\\" + this.parsedResults.getOutputDir() + "\\" + this.resultRequest.getXmlResultFile().getName()))));
                    this.requestBody.setText(this.resultRequest.getXmlString());
                    this.requestBody.setCaretPosition(0);

                } catch (IOException e) {
                    this.requestBody.setText(UiConstants.EMPTY_MESSAGE_STRING);
                }

                break;
            }
        }
    }

    /**
     * Generates window title
     *
     * @param result resultRequest from which the title is generated
     * @return generated window title
     */
    private String generateTitle(Result result) {

        String title = "Unknown Message";

        if (this.resultRequest != null) {
            title = "";
            title = title + result.getMessageInfo().getRequestName() + " - ";
            title = title + Configuration.dttmFormat.format(result.getMsgRcvDttm()) + " - ";
            title = title + result.getId();
        }

        return title + UiConstants.APP_WND_TITLE;
    }

    /**
     * Attempts to find specified search string in given result area
     *
     * @throws exceptions.NoMatchFoundException
     *          thrown when no matching string is found within message body
     */
    public void findIn() throws NoMatchFoundException {

        if (this.oldSearchString != null && !this.oldSearchString.equals(this.searchString.getText())) {
            this.searchSource.setCaretPosition(0);
            this.oldSearchString = null;
            this.foundMatch = false;
        }

        boolean stringFound = SearchEngine.find(this.searchSource, this.searchString.getText(), true, false, false, false);

        if (!stringFound && !this.foundMatch) {
            throw new NoMatchFoundException(this.searchString.getText());

        } else if (stringFound && !this.foundMatch) {
            this.foundMatch = true;
            this.oldSearchString = this.searchString.getText();

        } else if (!stringFound && this.foundMatch) {
            this.searchSource.setCaretPosition(0);
            SearchEngine.find(this.searchSource, this.searchString.getText(), true, false, false, false);
        }
    }

    /**
     * Resets search values
     */
    public void resetFindIn() {

        this.searchPanel.setVisible(false);
        this.searchString.setText("");

        if (this.searchSource != null) this.searchSource.requestFocus();
        if (this.resultForm != null) this.resultForm.repaint();

        this.searchSource = null;
        this.foundMatch = false;
    }

    /**
     * Creates SearchResult frame
     */
    public void createResultForm() {
        this.resultForm = new JFrame(this.generateTitle(this.resultRequest));
        this.resultForm.setContentPane(this.searchResult);
        this.resultForm.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        this.resultForm.setIconImage(Configuration.ICON_DEFAULT_FRAME);
        this.resultForm.pack();
        this.resultForm.setVisible(true);

        SearchResultFormWindowListener searchResultFormWindowListener = new SearchResultFormWindowListener(this);
        this.resultForm.addWindowStateListener(searchResultFormWindowListener);
        this.resultForm.addComponentListener(searchResultFormWindowListener);
    }

    /**
     * Creates models fields and sets
     * their properties to properly display
     * XML files
     */
    private void createUIComponents() {

        this.requestBody = new RSyntaxTextArea();
        this.requestBody.setWrapStyleWord(true);
        this.requestBody.setLineWrap(true);
        this.requestBody.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_XML);
        this.requestBody.setCurrentLineHighlightColor(Color.WHITE);

        this.responseBody = new RSyntaxTextArea();
        this.responseBody.setWrapStyleWord(true);
        this.responseBody.setLineWrap(true);
        this.responseBody.setCurrentLineHighlightColor(Color.WHITE);
        this.responseBody.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_XML);

        this.saveRequest = new JButton(Configuration.ICON_SAVE);
        this.saveResponse = new JButton(Configuration.ICON_SAVE);
        this.merge = new JButton(Configuration.ICON_MERGE);
    }

    public JScrollPane getRequestPanel() {
        return requestPanel;
    }

    public JPanel getButtonsPanel() {
        return buttonsPanel;
    }

    public JButton getSaveRequest() {
        return saveRequest;
    }

    public JButton getSaveResponse() {
        return saveResponse;
    }

    public JButton getMerge() {
        return merge;
    }

    public Result getResultRequest() {
        return resultRequest;
    }

    public Result getResultResponse() {
        return resultResponse;
    }

    public JFrame getResultForm() {
        return resultForm;
    }

    public RSyntaxTextArea getRequestBody() {
        return requestBody;
    }

    public RSyntaxTextArea getResponseBody() {
        return responseBody;
    }

    public JTextField getSearchString() {
        return searchString;
    }

    public JButton getFindIn() {
        return findIn;
    }

    public JPanel getSearchPanel() {
        return searchPanel;
    }

    public JTextArea getSearchSource() {
        return searchSource;
    }

    public void setSearchSource(RSyntaxTextArea searchSource) {
        this.searchSource = searchSource;
    }

    public JLabel getFindInLabel() {
        return findInLabel;
    }

    public JSplitPane getResultSplitPane() {
        return resultSplitPane;
    }
}
